package com.foftact.etfweekly;

import com.foftact.etfweekly.mapper.ETFWeeklyMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * ETF周线数据服务实现类
 * 实现ETF周线数据的业务逻辑，包括数据抓取、数据存在性判断和特定更新逻辑等
 */
@Service
public class ETFWeeklyServiceImpl implements ETFWeeklyService {

    private static final Logger logger = LoggerFactory.getLogger(ETFWeeklyServiceImpl.class);
    private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd");
    private static final String API_URL = "http://api.example.com/etf/history";
    private static final int RECENT_RECORDS_LIMIT = 10;
    private static final int FORCE_UPDATE_LIMIT = 3;

    @Autowired
    private ETFWeeklyMapper etfWeeklyMapper;

    @Override
    @Transactional
    public boolean fetchAndSaveETFWeeklyData(String code) {
        logger.info("开始抓取ETF周线数据，代码: {}", code);

        // 1. 获取最近10条数据，检查数据是否已存在
        List<ETFWeekly> recentData = etfWeeklyMapper.selectRecentByCode(code, RECENT_RECORDS_LIMIT);
        boolean needFetchAll = false;

        // 检查最近10条数据是否完整
        if (recentData.size() < RECENT_RECORDS_LIMIT) {
            needFetchAll = true;
            logger.info("最近10条数据不完整，需要抓取近1年所有数据，代码: {}", code);
        }

        // 2. 从API抓取周线数据
        List<ETFWeekly> weeklyData = fetchWeeklyDataFromApi(code, needFetchAll);
        logger.info("抓取到周线数据条数: {}", weeklyData.size());

        // 3. 使用自定义的写入更新逻辑处理数据
        boolean result = writeOrUpdateETFWeeklyData(code, weeklyData);
        logger.info("ETF周线数据保存完成，代码: {}, 结果: {}", code, result);
        return result;
    }

    @Override
    public List<ETFWeekly> getETFWeeklyByCodeAndDateRange(String code, String startDate, String endDate) {
        try {
            Date start = SDF.parse(startDate);
            Date end = SDF.parse(endDate);
            return etfWeeklyMapper.selectByCodeAndDateRange(code, start, end);
        } catch (ParseException e) {
            logger.error("日期格式解析错误", e);
            return new ArrayList<>();
        }
    }

    @Override
    public List<ETFWeekly> getAllETFWeekly() {
        return etfWeeklyMapper.selectAll();
    }

    @Override
    public boolean saveETFWeekly(ETFWeekly etfWeekly) {
        try {
            // 设置更新时间
            Date now = new Date();
            etfWeekly.setUpdateTime(now);
            etfWeekly.setDataSource("API");
            
            int result = etfWeeklyMapper.insert(etfWeekly);
            return result > 0;
        } catch (Exception e) {
            logger.error("保存ETF周线数据失败", e);
            return false;
        }
    }

    @Override
    public boolean batchSaveETFWeekly(List<ETFWeekly> etfWeeklyList) {
        try {
            Date now = new Date();
            for (ETFWeekly etfWeekly : etfWeeklyList) {
                // 检查是否已存在该数据
                ETFWeekly existing = etfWeeklyMapper.selectByCodeAndWeekDate(
                        etfWeekly.getCode(), etfWeekly.getWeekDate());
                
                if (existing != null) {
                    // 更新现有数据
                    etfWeekly.setId(existing.getId());
                    etfWeekly.setUpdateTime(now);
                    etfWeeklyMapper.update(etfWeekly);
                } else {
                    // 插入新数据
                    etfWeekly.setUpdateTime(now);
                    etfWeekly.setDataSource("API");
                    etfWeeklyMapper.insert(etfWeekly);
                }
            }
            return true;
        } catch (Exception e) {
            logger.error("批量保存ETF周线数据失败", e);
            return false;
        }
    }

    @Override
    public boolean updateETFWeekly(ETFWeekly etfWeekly) {
        try {
            etfWeekly.setUpdateTime(new Date());
            int result = etfWeeklyMapper.update(etfWeekly);
            return result > 0;
        } catch (Exception e) {
            logger.error("更新ETF周线数据失败", e);
            return false;
        }
    }

    @Override
    public boolean deleteETFWeekly(Long id) {
        try {
            int result = etfWeeklyMapper.deleteById(id);
            return result > 0;
        } catch (Exception e) {
            logger.error("删除ETF历史数据失败", e);
            return false;
        }
    }

    @Override
    public boolean deleteETFWeeklyByCodeAndDate(String code, String weekDate) {
        try {
            Date date = SDF.parse(weekDate);
            int result = etfWeeklyMapper.deleteByCodeAndWeekDate(code, date);
            return result > 0;
        } catch (ParseException e) {
            logger.error("日期格式解析错误", e);
            return false;
        }
    }

    @Override
    public List<ETFWeekly> getRecentETFWeeklyByCode(String code, Integer limit) {
        return etfWeeklyMapper.selectRecentByCode(code, limit);
    }
    
    @Override
    @Transactional
    public boolean writeOrUpdateETFWeeklyData(String code, List<ETFWeekly> dataList) {
        try {
            logger.info("开始处理ETF周线数据写入/更新逻辑，代码: {}", code);
            
            // 获取最近10条数据
            List<ETFWeekly> recent10Data = etfWeeklyMapper.selectRecentByCode(code, RECENT_RECORDS_LIMIT);
            Set<String> recent10Dates = recent10Data.stream()
                    .map(data -> SDF.format(data.getWeekDate()))
                    .collect(Collectors.toSet());

            // 按日期排序并获取最新的10条记录日期
            List<String> latest10FromDataList = dataList.stream()
                    .sorted(Comparator.comparing(ETFWeekly::getWeekDate).reversed())
                    .limit(RECENT_RECORDS_LIMIT)
                    .map(data -> SDF.format(data.getWeekDate()))
                    .collect(Collectors.toList());

            // 找出在dataList中但不在recent10Data中的记录
            Set<String> onlyInDataList = latest10FromDataList.stream()
                    .filter(date -> !recent10Dates.contains(date))
                    .collect(Collectors.toSet());

            // 检查最近10条数据是否完整
            boolean needUpdateAll = onlyInDataList.size() == 0;
            
            // 获取最近3条需要强制更新的数据
            List<ETFWeekly> recent3Data = recent10Data.stream()
                    .limit(FORCE_UPDATE_LIMIT)
                    .collect(Collectors.toList());
            Set<String> forceUpdateDates = recent3Data.stream()
                    .map(data -> SDF.format(data.getWeekDate()))
                    .collect(Collectors.toSet());
            
            // 准备需要保存的数据
            List<ETFWeekly> dataToSave = new ArrayList<>();
            Date now = new Date();
            
            // 按日期排序，确保时间顺序
            dataList.sort(Comparator.comparing(ETFWeekly::getWeekDate));
            
            for (ETFWeekly data : dataList) {
                String dataDate = SDF.format(data.getWeekDate());

                // 设置必要字段
                data.setCode(code);
                data.setUpdateTime(now);
                data.setDataSource("API");

                // 规则1: 如果近10条数据完整且当前数据在近10条中且不在近3条中，则跳过
                // 规则2: 如果近10条数据不完整，或者当前数据不在近10条中，或者当前数据在近3条中，则处理
                if (needUpdateAll || !recent10Dates.contains(dataDate) || forceUpdateDates.contains(dataDate)) {
                    dataToSave.add(data);
                }
            }

            // 批量查询已存在的数据
            Map<String, ETFWeekly> existingDataMap = new HashMap<>();
            if (!dataToSave.isEmpty()) {
                List<String> datesToCheck = dataToSave.stream()
                        .map(data -> SDF.format(data.getWeekDate()))
                        .collect(Collectors.toList());
                List<ETFWeekly> existingList = etfWeeklyMapper.selectByCodeAndWeekDates(code, datesToCheck);
                existingDataMap = existingList.stream()
                        .collect(Collectors.toMap(
                                item -> SDF.format(item.getWeekDate()),
                                item -> item
                        ));
            }

            // 为需要保存的数据设置ID（如果已存在）
            for (ETFWeekly data : dataToSave) {
                String dataDate = SDF.format(data.getWeekDate());
                ETFWeekly existing = existingDataMap.get(dataDate);
                if (existing != null) {
                    data.setId(existing.getId());
                }
            }

            int totalUpdatedSize = 0;
            // 执行批量保存/更新 (使用 ON DUPLICATE KEY UPDATE)
            if (!dataToSave.isEmpty()) {
                logger.info("需要保存/更新的数据条数: {}", dataToSave.size());

                // 拆分成每批次最多10条记录
                int batchSize = 10;

                for (int i = 0; i < dataToSave.size(); i += batchSize) {
                    int endIndex = Math.min(i + batchSize, dataToSave.size());
                    List<ETFWeekly> batchData = dataToSave.subList(i, endIndex);
                    // 假设 ETFWeeklyMapper 中添加了 batchInsertOrUpdate 方法
                    int batchUpdatedSize = etfWeeklyMapper.batchInsertOrUpdate(batchData);
                    logger.info("已完成批次保存/更新，当前批次数据条数: {}", batchUpdatedSize);
                    totalUpdatedSize += batchUpdatedSize;
                }

            }
            
            logger.info("ETF周线数据写入/更新完成，代码: {} 数量{}", code, totalUpdatedSize);
            return true;
        } catch (Exception e) {
            logger.error("处理ETF周线数据写入/更新失败，代码: {}", code, e);
            return false;
        }
    }

    @Override
    public boolean truncateETFWeeklyTable() {
        try {
            int result = etfWeeklyMapper.truncateTable();
            return result >= 0;
        } catch (Exception e) {
            logger.error("清空ETF周线表失败", e);
            return false;
        }
    }

    /**
     * 从API抓取周线数据
     */
    private List<ETFWeekly> fetchWeeklyDataFromApi(String code, boolean needFetchAll) {
        List<ETFWeekly> weeklyData = new ArrayList<>();
        try {
            // 这里模拟API调用，实际应用中应该使用HTTP客户端如HttpClient或RestTemplate
            // 示例代码，实际需替换为真实API调用
            for (int page = 1; page <= 10; page++) { // 模拟多页抓取
                // 模拟API响应数据
                List<ETFWeekly> pageData = simulateWeeklyApiResponse(code, page, needFetchAll);
                if (pageData.isEmpty()) {
                    break;
                }
                weeklyData.addAll(pageData);
            }
        } catch (Exception e) {
            logger.error("从API抓取周线数据失败", e);
        }
        return weeklyData;
    }

    /**
     * 模拟周线数据API响应（仅用于示例）
     */
    private List<ETFWeekly> simulateWeeklyApiResponse(String code, int page, boolean needFetchAll) throws ParseException {
        List<ETFWeekly> data = new ArrayList<>();
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DAY_OF_YEAR, -page * 35); // 模拟历史数据，按周
        
        // 每页返回10周数据
        for (int i = 0; i < 10; i++) {
            ETFWeekly record = new ETFWeekly();
            record.setCode(code);
            record.setMarket(code.startsWith("00") ? 0 : 1); // 0: 沪市, 1: 深市
            record.setName("ETF产品" + code);
            record.setWeekDate(cal.getTime());
            
            // 生成模拟数据
            BigDecimal randomPrice = BigDecimal.valueOf(1.0 + Math.random() * 0.5);
            record.setOpen(randomPrice);
            record.setClose(randomPrice.add(BigDecimal.valueOf(Math.random() * 0.1 - 0.05)));
            record.setHigh(record.getClose().add(BigDecimal.valueOf(Math.random() * 0.03)));
            record.setLow(record.getClose().subtract(BigDecimal.valueOf(Math.random() * 0.03)));
            record.setVolume(Math.round(Math.random() * 10000000));
            record.setAmount(BigDecimal.valueOf(record.getVolume()).multiply(record.getClose()));
            
            // 计算涨跌幅和涨跌额
            if (i > 0 && !data.isEmpty()) {
                ETFWeekly prevRecord = data.get(data.size() - 1);
                record.setChangeAmount(record.getClose().subtract(prevRecord.getClose()));
                if (prevRecord.getClose().compareTo(BigDecimal.ZERO) > 0) {
                    record.setChangePercent(record.getChangeAmount().divide(prevRecord.getClose(), 4, BigDecimal.ROUND_HALF_UP)
                            .multiply(new BigDecimal(100)));
                }
            }
            
            record.setDataSource("API");
            record.setUpdateTime(new Date());
            
            data.add(record);
            cal.add(Calendar.DAY_OF_YEAR, -7); // 每周数据间隔7天
        }
        
        // 反转列表，使最新的数据在最后
        Collections.reverse(data);
        return data;
    }

    /**
     * 解析BigDecimal
     */
    private BigDecimal parseBigDecimal(String value) {
        if (value == null || value.isEmpty()) {
            return BigDecimal.ZERO;
        }
        try {
            return new BigDecimal(value);
        } catch (NumberFormatException e) {
            return BigDecimal.ZERO;
        }
    }

    // 原有模拟API响应数据方法已替换为周线数据模拟方法
}